3.1: The Android Studio Debugger
Contents:
- Introduction
- About debugging
- Running the debugger
- Using Breakpoints
- Stepping through code
- Viewing execution stack frames
- Inspecting and modifying variables
- Setting watches
- Evaluating expressions
- More tools for debugging
- Trace logging and the Android manifest
- Related practical
- Learn more
In this chapter you'll learn about debugging your apps in Android Studio.
About debugging
Debugging is the process of finding and fixing errors (bugs) or unexpected behavior in your code. All code has bugs, from incorrect behavior in your app, to behavior that excessively consumes memory or network resources, to actual app freezing or crashing.
Bugs can result for many reasons:
- Errors in your design or implementation.
- Android framework limitations (or bugs).
- Missing requirements or assumptions for how the app should work.
- Device limitations (or bugs)
Use the debugging, testing, and profiling capabilities in Android Studio to help you reproduce, find, and resolve all of these problems. Those capabilities include:
- The Android monitor (logcat)
- The Android Studio debugger
- Testing frameworks such as JUnit or Espresso
- Dalvik Debug Monitor Server (DDMS), to track resource usage
In this chapter you'll learn how to debug your app with the Android Studio debugger, set and view breakpoints, step through your code, and examine variables.
Running the debugger
Running an app in debug mode is similar to just running that app. You can either run an app in debug mode, or attach the debugger to an already-running app.
Run your app in debug mode
To start debugging, click Debug in the toolbar. Android Studio builds an APK, signs it with a debug key, installs it on your selected device, then runs it and opens the Debug window.
Debug a running app
If your app is already running on a device or emulator, start debugging that app with these steps:
- Select Run > Attach debugger to Android process or click the Attach icon in the toolbar.
In the Choose Process dialog, select the process to which you want to attach the debugger.
By default, the debugger shows the device and app process for the current project, as well as any connected hardware devices or virtual devices on your computer. Select Show all processes to show all processes on all devices.
- Click OK. The Debug window appears as before.
Resume or Stop Debugging
To resume executing an app after debugging it, select Run > Resume Program or click the Resume icon.
To stop debugging your app, select Run > Stop or click the Stop icon in the toolbar.
Using Breakpoints
A breakpoint is a place in your code where you want to pause the normal execution of your app to perform other actions such as examining variables or evaluating expressions, or executing your code line by line to determine the causes of runtime errors.
Add breakpoints
To add a breakpoint to a line in your code, use these steps:
- Locate the line of code where you want to pause execution.
Click in the left gutter of the editor window at that line, next to the line numbers. A red dot appears at that line, indicating a breakpoint.
You can also use Run > Toggle Line Breakpoint or Control-F8 (Command-F8 on OS X) to set a breakpoint at a line.
If your app is already running, you don't need to update it to add the breakpoint.
When your code execution reaches the breakpoint, Android Studio pauses execution of your app. You can then use the tools in the Android debugger to view the state of the app and debug that app as it runs.
View and configure breakpoints
To view all the breakpoints you've set and configure breakpoint settings, click the View Breakpoints icon on the left edge of the debugger window. The Breakpoints window appears.
In this window all the breakpoints you have set appear in the left pane, and you can enable or disable each breakpoint with the check boxes. If a breakpoint is disabled, Android Studio does not pause your app when execution reaches that breakpoint.
Select a breakpoint from the list to configure its settings. You can configure a breakpoint to be disabled at first and have the system enable it after a different breakpoint is encountered. You can also configure whether a breakpoint should be disabled after it has been reached.
To set a breakpoint for any exception, select Exception Breakpoints in the list of breakpoints.
Disable (Mute) all breakpoints
Disabling a breakpoint enables you to temporarily "mute" that breakpoint without removing it from your code. If you remove a breakpoint altogether you also lose any conditions or other features you created for that breakpoint, so disabling it can be a better choice.
To mute all breakpoints, click the Mute Breakpoints icon. Click the icon again to enable (unmute) all breakpoints.
Use conditional breakpoints
Conditional breakpoints are breakpoints that only stop execution of your app if the test in the condition is true. To define a test for a conditional breakpoint, use these steps:
Right click on a breakpoint icon, and enter a test in the Condition field.
You can also use the Breakpoints window to enter a breakpoint condition.
The test you enter in this field can be any Java expression as long as it returns a boolean value. You can use variable names from your app as part of the expression.
- Run your app in debug mode. Execution of your app stops at the conditional breakpoint, if the condition evaluates to true.
Stepping through code
After your app's execution has stopped because a breakpoint has been reached, you can execute your code from that point one line at a time with the Step Over, Step Into, and Step Out functions.
To use any of the step functions:
Begin debugging your app. Pause the execution of your app with a breakpoint.
Your app's execution stops, and the debugger shows the current state of the app. The current line is highlighted in your code.
Click the Step Over icon, select Run > Step Over, or type F8.
Step Over executes the next line of the code in the current class and method, executing all of the method calls on that line and remaining in the same file.
Click the Step Into icon, select Run > Step Into, or type F7.
Step Into jumps into the execution of a method call on the current line (versus just executing that method and remaining on the same line). The Frames view (which you'll learn about in the next section) updates to show the new stack frame (the new method). If the method call is contained in another class, the file for that class is opened and the current line in that file is highlighted. You can continue stepping over lines in this new method call, or step deeper into other methods.
Click the Step Out icon, select Run > Step Out, or type Shift-F8.
Step Out finishes executing the current method and returns to the point where that method was called.
- To resume normal execution of the app, select Run > Resume Program or click the Resume icon.
Viewing execution stack frames
The Frames view of the debugger window allows you to inspect the execution stack and the specific frame that caused the current breakpoint to be reached.
The execution stack shows all the classes and methods (frames) that are being executed up to this point in the app, in reverse order (most recent frame first). As execution of a particular frame finishes, that frame is popped from the stack and execution returns to the next frame.
Clicking a line for a frame in the Frames view opens the associated source in the editor and highlights the line where that frame was initially executed. The Variables and Watches views also update to reflect the state of the execution environment when that frame was last entered.
Inspecting and modifying variables
The Variables view of the debugger window allows you to inspect the variables available at the current stack frame when the system stops your app on a breakpoint. Variables that hold objects or collections such as arrays can be expanded to view their components.
The Variables pane also allows you to evaluate expressions on the fly using static methods and/or variables available within the selected frame.
If the Variables view is not visible, click the Restore Variables View icon .
To modify variables in your app as it runs:
- Right-click any variable in the Variables view, and select Set Value. You can also use F2.
Enter a new value for the variable, and type Return.
The value you enter must be of the appropriate type for that variable, or Android Studio returns a "type mismatch" error.
Setting watches
The Watches view provides similar functionality to the Variables view except that expressions added to the Watches pane persist between debugging sessions. Add watches for variables and fields that you access frequently or that provide state that is helpful for the current debugging session.
To use watches:
- Begin debugging your app.
In the Watches pane, click the plus (+) button.
In the text box that appears, type the name of the variable or expression you want to watch and then press Enter.
Remove an item from the Watches list by selecting the item and then clicking the minus (-) button.
Change the order of the elements in the Watches list by selecting an item and then clicking the up or down icons.
Evaluating expressions
Use Evaluate Expression to explore the state of variables and objects in your app, including calling methods on those objects. To evaluate an expression:
Click the Evaluate Expression icon, or select Run > Evaluate Expression. You can also right-click on any variable and choose Evaluate Expression.
The Evaluate Expression window appears.
Enter any expression into the Expression window and click Evaluate.
The Evaluate Expression window updates with the result of the execution. Note that the result you get from evaluating an expression is based on the app's current state. Depending on the values of the variables in your app at the time you evaluate expressions, you may get different results. Changing the values of variables in your expressions also changes the current running state of the app.
More tools for debugging
Android Studio and the Android SDK include a number of other tools to help you find and correct issues in your code. These tools include:
- System log (logcat). As you've learned in previous lessons, you can use the Log class to send messages to the Android system log, and view those messages in Android Studio.
- To write log messages in your code, use the Log class. Log messages help you understand the execution flow by collecting the system debug output while you interact with your app. Log messages can tell you what part of your application failed. For more information about logging, see Reading and Writing Logs.
- Tracing and Logging. Analyzing traces allows you to see how much time is spent in certain methods, and which ones are taking the longest times.
- To create the trace files, include the Debug class and and call one of the startMethodTracing() methods. In the call, you specify a base name for the trace files that the system generates. To stop tracing, call stopMethodTracing(). These methods start and stop method tracing across the entire virtual machine. For example, you could call startMethodTracing() in your activity's onCreate() method, and call stopMethodTracing() in that activity's onDestroy() method.
- The Android Debug Bridge (ADB). ADB is a command-line tool that lets you communicate with an emulator instance or connected Android-powered device.
- Dalvik Debug Monitor Server (DDMS). The DDSM tool provides port-forwarding services, screen capture, thread and heap information, logcat, process, and radio state information, incoming call and SMS spoofing, location data spoofing, and more.
- CPU and memory monitors. Android Studio includes a number of monitors to help you visualize the behavior and performance of your app.
- Screenshot and video capture.
Trace logging and the Android manifest
There are multiple types of debugging available to you beyond setting breakpoints and stepping through code. You can also use logging and tracing to find issues with your code. When you have a trace log file (generated by adding tracing code to your application or by DDMS), you can load the log files in Traceview, which displays the log data in two panels:
- A timeline panel -- describes when each thread and method started and stopped
- A profile panel -- provides a summary of what happened inside a method
Likewise, you can set android:debuggable in the <application>
tag of the Android Manifest to "true"
, which sets whether or not the application can be debugged, even when running on a device in user mode. By default, this value is set to "false"
.
You can create and configure build types in the module-level build.gradle file inside the android {} block. When you create a new module, Android Studio automatically creates the debug and release build types for you. Although the debug build type doesn't appear in the build configuration file, Android Studio configures it with debuggable true. This allows you to debug the app on secure Android devices and configures APK signing with a generic debug keystore. You can add the the debug build type to your configuration if you want to add or change certain settings.
All these changes made for debugging must be removed from your code before release because they can impact the execution and performance production code.
When you prepare your app for release, you must remove all the extra code in your source files that you wrote for testing purposes.
In addition to prepping the code itself, there are a few other tasks you need to complete in order to get your app ready to publish. These include:
- Removing logging statements
- Remove any calls to show Toasts
- Disable debugging in the Android manifest by either:
- Removing android:debuggable attribute from
<application>
tag - Or setting android:debuggable attribute to false
- Removing android:debuggable attribute from
Remove all debug tracing calls from your source code files such as startMethodTracing() and stopMethodTracing().
Related practical
The related exercises and practical documentation is in Android Developer Fundamentals: Practicals.